package com.atguigu.crowd.service.impl;

import com.atguigu.crowd.constant.CrowdConstant;
import com.atguigu.crowd.entity.Admin;
import com.atguigu.crowd.entity.AdminExample;
import com.atguigu.crowd.exception.LoginAcctAlreadyInUseException;
import com.atguigu.crowd.exception.LoginAcctAlreadyInUseForUpdateException;
import com.atguigu.crowd.exception.LoginFailedException;
import com.atguigu.crowd.mapper.AdminMapper;
import com.atguigu.crowd.service.api.AdminService;
import com.atguigu.crowd.util.CrowdUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.aspectj.weaver.bcel.BcelAccessForInlineMunger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service("")
public class AdminServiceImpl implements AdminService {

    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;




    @Override
    public void saveAdmin(Admin admin) {
      //  BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        //1.密码加密 使用spring security的带盐值加密
        String userPswd = admin.getUserPswd();
       // userPswd = CrowdUtil.md5(admin.getUserPswd());
         userPswd = passwordEncoder.encode(userPswd);
          admin.setUserPswd(userPswd);

        //2.生成创建时间
        Date date=new Date();
        SimpleDateFormat simpleDateFormat =
                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String creatTime = simpleDateFormat.format(date);
        admin.setCreateTime(creatTime);

        //3.执行保存
        //需要异常处理 若输入重复的用户账号 会抛出异常：重复
        // 在自定义异常处理器中处理LoginAcctAlreadyInUseException自定义异常类
        //使用自定义异常是因为 可能不止账号重复 其他表设置了唯一约束的 系统也会抛出DuplicateKeyException
        //若都直接用自定义异常处理器处理DuplicateKeyException 可能出现异常与处理不一致的情况
        try {
            adminMapper.insert(admin);
        }catch (Exception e){
            e.printStackTrace();
            //这里spring会检测出异常DuplicateKeyException
            // 然后用自己写的异常类进行处理
            //之前的登录失败异常 是自己要求的异常 系统不会抛出异常 这里数据库有唯一索引 系统会抛出异常
            if(e instanceof DuplicateKeyException){
                //抛出异常都会经过自定义异常处理器进行处理
                throw new LoginAcctAlreadyInUseException(CrowdConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
            }
        }

    }

    @Override
    public List<Admin> getAll() {
        return adminMapper.selectByExample(new AdminExample());
    }

    @Override
    public Admin getAdminByLoginAcct(String loginAcct, String userPswd) {
        //1.根据登录账户查询Admin对象
         //创建AdminExample对象
        AdminExample adminExample = new AdminExample();
        
        //创建Criteria对象
        AdminExample.Criteria criteria = adminExample.createCriteria();

        //在Criteria对象中封装查询条件
        criteria.andLoginAcctEqualTo(loginAcct);

        //调用方法执行查询
        List<Admin> list = adminMapper.selectByExample(adminExample);

        //2.判断Admin对象是否为空
        if(list == null || list.size() == 0){
            throw new LoginFailedException(CrowdConstant.MESSAGE_LOGIN_FAILED);
        }

        if(list.size() >1){
            //系统错误
            throw new RuntimeException(CrowdConstant.MESSAGE_SYSTEM_ERROR_LOGIN_NOT_UNIQUE);
        }

        Admin admin=list.get(0);
        
        //3.如果Admin为空 抛出异常
        if(admin == null){
            throw new LoginFailedException(CrowdConstant.MESSAGE_LOGIN_FAILED);
        }
        
        //4.不为空 将数据库密码从Admin对象取出
        String userPswdDB = admin.getUserPswd();

        //5.将表单提交的明文密码加密
        String userPswdForm = CrowdUtil.md5(userPswd);

        //6.对密码进行比较
        if(!Objects.equals(userPswdDB,userPswdForm)){
            //7.比较结果不一致 抛出异常 自定义异常
            throw new LoginFailedException(CrowdConstant.MESSAGE_LOGIN_FAILED);
        }

        //8.比较结果一致 返回Admin对象
        return admin;
    }


      //spring security的查询
    @Override
    public Admin getAdminByLoginAcct(String username) {
        AdminExample example = new AdminExample();

        AdminExample.Criteria criteria = example.createCriteria();

        criteria.andLoginAcctEqualTo(username);

        List<Admin> list = adminMapper.selectByExample(example);

        Admin admin = list.get(0);

        return admin;
    }

    @Override
    public PageInfo<Admin> getPageInfo(String keyword, Integer pageNum, Integer pageSize) {

        //1.调用PageHelper的静态方法开启分页功能
        //体现了PageHelper的非侵入式设计 原本要做的查询不必要做任何修改
        PageHelper.startPage(pageNum,pageSize);
        
        //2.执行查询
        List<Admin> list = adminMapper.selectAdminByKeyword(keyword);

        //3.封装到PageInfo对象中
        return new PageInfo<>(list);

    }

    /**
     * 用户维护页面 单条删除 以后也可以用于其他的删除
     * @param adminId
     */
    @Override
    public void remove(Integer adminId) {
        adminMapper.deleteByPrimaryKey(adminId);
    }

    /**
     * 根据ID查admin对象
     * @param adminId
     * @return
     */
    @Override
    public Admin getAdminById(Integer adminId) {
        Admin admin = adminMapper.selectByPrimaryKey(adminId);
        return admin;
    }

    /**
     * 更新
     * @param admin
     */
    @Override
    public void update(Admin admin) {
        //"Selective"表示有选择的更新 对于null值的字段不更新
        //若账号重复 处理异常
        try {
            adminMapper.updateByPrimaryKeySelective(admin);
        }catch (Exception e){
            e.printStackTrace();
           if(e instanceof DuplicateKeyException){
               //抛出异常都会经过自定义异常处理器进行处理
                throw new LoginAcctAlreadyInUseForUpdateException(CrowdConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
            }
        }
    }

    /**
     * 保存 一个用户分配的角色
     * @param adminId
     * @param roleIdList
     */
    @Override
    public void saveAdminRoleRelationship(Integer adminId, List<Integer> roleIdList) {
        //只需要将adminID与对应的roleId存入关联表即可 不需要roleName等其它

        //注意：adminID之前可能有旧的关系 为了简化操作 先将旧关系删除
        //再根据roleIdList添加新关系进入关系表

        //1.根据 adminId 删除旧的关联关系数据
        adminMapper.deleteOLdRelationship(adminId);
        //2.根据 roleIdList 和 adminId 保存新的关联关系
        if(roleIdList!=null && roleIdList.size()>0){
            adminMapper.insertNewRelationship(adminId,roleIdList);
        }

    }


}
